package org.zhxy.core.system.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zhxy.entity.system.ErrorLog;
import com.zhxy.entity.system.OptionalLog;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import org.zhxy.common.aop.AutomaticLog;
import org.zhxy.common.base.BaseService;
import org.zhxy.common.response.PageResult;
import org.zhxy.core.system.mapper.ErrorLogMapper;
import org.zhxy.core.system.mapper.OptionalLogMapper;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.*;

@Service
@Transactional
public class LogService extends BaseService {


    @Autowired
    private ErrorLogMapper errorLogMapper;

    @Autowired
    private OptionalLogMapper optionalLogMapper;

    @Autowired
    private ObjectMapper objectMapper;

    public PageResult getErrorLogList(Map<String, Object> map) {
        Integer page = Integer.parseInt(map.get("page").toString());
        Integer size = Integer.parseInt(map.get("size").toString());
        IPage<ErrorLog> iPage = new Page<>(page,size);
        QueryWrapper<ErrorLog> queryWrapper = new QueryWrapper<>();
        if(map.get("modifyUser") != null) queryWrapper.like("modify_user",map.get("modifyUser").toString());
        if(map.get("operation") != null) queryWrapper.like("operation",map.get("operation").toString());
        queryWrapper.orderByDesc("create_time");
        IPage<ErrorLog> result = errorLogMapper.selectPage(iPage, queryWrapper);
        return new PageResult<ErrorLog>(result.getTotal(),result.getRecords());
    }

    public PageResult getOptionalLogList(Map<String, Object> map) {
        Integer page = Integer.parseInt(map.get("page").toString());
        Integer size = Integer.parseInt(map.get("size").toString());
        IPage<OptionalLog> iPage = new Page<>(page,size);
        QueryWrapper<OptionalLog> queryWrapper = new QueryWrapper<>();
        if( map.get("username") != null) queryWrapper.like("username", map.get("username").toString());
        if(map.get("operation") != null) queryWrapper.like("operation",map.get("operation").toString());
        queryWrapper.orderByDesc("create_time");
        IPage<OptionalLog> result = optionalLogMapper.selectPage(iPage, queryWrapper);
        return new PageResult<OptionalLog>(result.getTotal(),result.getRecords());
    }


    public void saveOptionalLog(ProceedingJoinPoint point, OptionalLog log) throws JsonProcessingException {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        AutomaticLog logAnnotation = method.getAnnotation(AutomaticLog.class);
        if(logAnnotation != null){
            log.setOperation(logAnnotation.value());
        }
        String methodName = signature.getName();
        log.setMethod(point.getTarget() + ":" + methodName + "()");
        Object[] args = point.getArgs();
        LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer();
        String[] parameterNames = u.getParameterNames(method);
        if(args != null &&parameterNames != null){
            StringBuilder params = new StringBuilder();
            params = this.handleParams(params,args, Arrays.asList(parameterNames));
            log.setParams(params.toString());
        }
        log.setCreateTime(new Date());
        Long beginTime = log.getTime();
        Long time = System.currentTimeMillis() - beginTime;
        log.setTime(time);
        optionalLogMapper.insert(log);
    }

    public void saveErrorLog(JoinPoint joinPoint, ErrorLog errorLog) throws JsonProcessingException {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        Object[] args = joinPoint.getArgs();
        LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer();
        String[] paramNames = u.getParameterNames(method);
        if (args != null && paramNames != null) {
            StringBuilder params = new StringBuilder();
            params = handleParams(params, args, Arrays.asList(paramNames));
            errorLog.setParams(params.toString());
        }
        AutomaticLog annotation = method.getAnnotation(AutomaticLog.class);
        String value = annotation.value();
        errorLog.setOperation(value);
        errorLogMapper.insert(errorLog);
    }



    private StringBuilder handleParams(StringBuilder params, Object[] args, List paramNames) throws JsonProcessingException {
        for (int i = 0; i < args.length; i++) {
            if (args[i] instanceof Map) {
                Set set = ((Map) args[i]).keySet();
                List<Object> list = new ArrayList<>();
                List<Object> paramList = new ArrayList<>();
                for (Object key : set) {
                    list.add(((Map) args[i]).get(key));
                    paramList.add(key);
                }
                return handleParams(params, list.toArray(), paramList);
            } else {
                if (args[i] instanceof Serializable) {
                    Class<?> aClass = args[i].getClass();
                    try {
                        aClass.getDeclaredMethod("toString", new Class[]{null});
                        params.append(" ").append(paramNames.get(i)).append(": ").append(objectMapper.writeValueAsString(args[i]));
                    } catch (NoSuchMethodException e) {
                        params.append(" ").append(paramNames.get(i)).append(": ").append(objectMapper.writeValueAsString(args[i].toString()));
                    }
                } else if (args[i] instanceof MultipartFile) {
                    MultipartFile file = (MultipartFile) args[i];
                    params.append(" ").append(paramNames.get(i)).append(": ").append(file.getName());
                } else {
                    params.append(" ").append(paramNames.get(i)).append(": ").append(args[i]);
                }
            }
        }
        return params;
    }
}

